package com.wonder.excel;

import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.streaming.SXSSFCell;
import org.apache.poi.xssf.streaming.SXSSFRow;
import org.apache.poi.xssf.streaming.SXSSFSheet;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.util.*;

/**
 *
 * @description: TODO
 * @author jinrong.wang
 * @date 2023.08.13
 * @version 1.0
 */
public class ExcelDealService {
    private final static Logger logger = LoggerFactory.getLogger(ExcelDealService.class);

    private final String RESULT_TRUE = "一致";
    private final String RESULT_FALSE = "不一致";
    //比较结果不一致的数据，单独放一个集合
    private List<Map<String, String>> excelFileCompareFalseData = new ArrayList<>();
    /**
     * 处理文件
     *
     * @param file1
     * @param file2
     * @param nameParams
     * @throws ExcelException
     */
    public SXSSFWorkbook dealFileUploadLocalService(File file1, File file2, List<String> nameParams) throws Exception {
        SXSSFWorkbook fileDownLoadKey =null;

        ExcelDataUtils excelDataUtils = new ExcelDataUtils();//new一个新实例。保证每次请求都是空的。
        excelDataUtils.initData(file1, file2, nameParams);//初始化数据，提取表头到listString，提取每一行数据到listMap
        //数据结构为->(file1文件每行的序列,查询参数组合的唯一key)
        Map<String, String> excel1_Duplication_key = excelDataUtils.getDuplicationRowidKeyMap(excelDataUtils.excelOnlyKey_FileData_1);//fileRowId,onlyKey
//        excelDataUtils.megerDate();//合并数据处理

        //生成文件
        try {
            fileDownLoadKey=createExcel(excelDataUtils.excel1Add2Head,
                    excelDataUtils.excelFileData_1,
                    excelDataUtils.excelOnlyKey_FileData_1, excelDataUtils.excelOnlyKey_FileData_2,
                    excelDataUtils.excelIntersection_1, excelDataUtils.excelIntersection_2,
                    excelDataUtils.head1SetIntersection, excelDataUtils.head2SetIntersection,
                    excel1_Duplication_key,
                    excelDataUtils.excel1Head, excelDataUtils.excel2Head
            );
        } catch (Exception e) {
            logger.error("异常{}", e);
            throw new ExcelException("生成比较文件异常" + e.getMessage());
        }
        return fileDownLoadKey;
    }


    /**
     * 比对结果-数据并集-表头并集
     * 比较结果是excelFile1跟excelFile2的左连接+excelfile2差集。可以理解为SQL的full join
     * 比对结果-数据并集-表头并集"的数据结构为如下
     * key,姓名,姓名,比较
     * key1,张三,张三,true
     * key2,李四,小王,false
     */

    public SXSSFWorkbook createExcel(List<String> excel1Add2Head,
                            List<Map<String, String>> excelFileData_1,
                            Map<String, Map<String, String>> excelOnlyKey_FileData_1, Map<String, Map<String, String>> excelOnlyKey_FileData_2,
                            Set<String> excelIntersection_1, Set<String> excelIntersection_2,
                            Set<String> head1SetIntersection, Set<String> head2SetIntersection,
                            Map<String, String> excel1_Duplication_key,
                            List<String> excel1Head, List<String> excel2Head

    ) throws ExcelException {
        //excel1Data条数是顺序的，excel1Add2Head 表头是顺序的。
        //新建工作簿
        SXSSFWorkbook workbook = new SXSSFWorkbook();

        SXSSFSheet sheet = workbook.createSheet("比对结果-数据并集-表头并集");
        SXSSFSheet sheet2 = workbook.createSheet("只在excel1存在的数据");
        SXSSFSheet sheet3 = workbook.createSheet("只在excel2存在的数据");
        SXSSFSheet sheet4 = workbook.createSheet("比较结果不一致的数据");
        this.excelFileCompareFalseData = new ArrayList<>();
        logger.info("比对结果-数据并集-表头并集，开始处理");
        //比对结果-数据并集-表头并集
        createCompareResult(excel1Add2Head, excel1_Duplication_key,
                excelFileData_1, head1SetIntersection,
                excelOnlyKey_FileData_2, excelIntersection_2,
                head2SetIntersection,
                workbook, sheet,true
        );
        System.out.println("比对结果-数据并集-表头并集,处理完成,条数为"+sheet.getLastRowNum());
        System.out.println("处理比较结果不一致的数据开始");
        //避免引用传递错误的问题，这里新建一个对象
        List<Map<String, String>> excelFileCompareFalseDataNew = new ArrayList<>();
        excelFileCompareFalseDataNew.addAll(this.excelFileCompareFalseData);
        createCompareResult(excel1Add2Head, excel1_Duplication_key,
                excelFileCompareFalseDataNew, head1SetIntersection,
                excelOnlyKey_FileData_2, excelIntersection_2,
                head2SetIntersection,
                workbook, sheet4,false
        );
        this.excelFileCompareFalseData = new ArrayList<>();
        System.out.println("处理比较结果不一致的数据完成");

        //只在excel1存在的数据
        createSheet(excelOnlyKey_FileData_1, excelIntersection_1, excel1Head, sheet2);
        logger.info("只在excel1存在的数据,处理完成");
        //只在excel2存在的数据
        createSheet(excelOnlyKey_FileData_2, excelIntersection_2, excel2Head, sheet3);
        logger.info("只在excel2存在的数据,处理完成");

//        String fileDownLoadKey = Constant.TEMPFILE_DIRECTORY+"/"+UUID.randomUUID().toString();
//        //搞一个文件夹存
//        try {
//            File file = new File(Constant.TEMPFILE_DIRECTORY);
//            Path path = Paths.get(Constant.TEMPFILE_DIRECTORY);
//            if (!Files.exists(path)) {
//                file.mkdir();
//            }
//        } catch (Exception e) {
//            logger.error("生成文件时异常",e);
//        }
//        //将工作簿写入文件系统
//        try (FileOutputStream fos = new FileOutputStream(fileDownLoadKey)) {
//            workbook.write(fos);
//            logger.info("文件={},写入成功",fileDownLoadKey);
//        } catch (IOException e) {
//            logger.error("生成文件时异常",e);
//            throw new ExcelException("生成文件异常");
//        }
//        logger.info("文件生成成功");
        return workbook;
    }

    public void createSheet(Map<String, Map<String, String>> excelOnlyKey_FileData,
                            Set<String> excelIntersection, List<String> excelHead,
                            SXSSFSheet sheet3) {
        //第0行为表头
        SXSSFRow row3_0 = sheet3.createRow(0);//创建一行
        SXSSFCell cell3_0 = row3_0.createCell(0);//第一个格子
        cell3_0.setCellValue("唯一key");//说明
        for (int i = 0; i < excelHead.size(); i++) {
            Cell cell = row3_0.createCell(i + 1);
            cell.setCellValue(excelHead.get(i));
        }
        int sheet3_rowid = 1;
        for (String s : excelIntersection) {
            SXSSFRow row = sheet3.createRow(sheet3_rowid);//创建一行
            sheet3_rowid++;
            /***********第0列，开始**************/
            SXSSFCell cell = row.createCell(0);
            cell.setCellValue(s);
            /***********第0列，结束**************/
            //从第二列开始，遍历每一个head，并从map取值赋值
            for (int i = 0; i < excelHead.size(); i++) {
                String headName = excelHead.get(i);
                Map<String, String> sheet2Map = excelOnlyKey_FileData.get(s);
                cell = row.createCell(i + 1);
                cell.setCellValue(sheet2Map.get(headName));
            }
        }
    }

    public SXSSFSheet createCompareResult(List<String> excel1Add2Head, Map<String, String> excel1_Duplication_key,
                                         List<Map<String, String>> excelFileData_1, Set<String> head1SetIntersection,
                                         Map<String, Map<String, String>> excelOnlyKey_FileData_2, Set<String> excelIntersection_2,
                                         Set<String> head2SetIntersection,
                                         SXSSFWorkbook workbook, SXSSFSheet sheet,boolean isCreateExcel2Date
    ) {
        Map<String, CellStyle> stringCellStyleMap = setCellStyleMap(workbook);
        CellStyle RED_GROUND = stringCellStyleMap.get("RED_GROUND");
        CellStyle LIGHT_BLUE_GROUND = stringCellStyleMap.get("LIGHT_BLUE_GROUND");
        CellStyle PINK_GROUND = stringCellStyleMap.get("PINK_GROUND");
        CellStyle SKY_BLUE_GROUND = stringCellStyleMap.get("SKY_BLUE_GROUND");
        CellStyle LIGHT_YELLOW_GROUND = stringCellStyleMap.get("LIGHT_YELLOW_GROUND");
        CellStyle RED_FONT = stringCellStyleMap.get("RED_FONT");
        /////////////////////遍历每一行数据////////////////////////////////////////////////////////
        //excel1的数据，excel1Data是excel的有序原始数据
        for (int i = 0; i < excelFileData_1.size(); i++) {
            boolean compareFlag=true;
            //导入文件的第i行数据
            Map<String, String> row_excelFileData_1 = excelFileData_1.get(i);
            //excel1_Duplication_key的数据结构->(file1文件每行的序列,查询参数组合的唯一key)
            String excelOnlyKey_1 = excel1_Duplication_key.get(row_excelFileData_1.get(Constant.FILEROWID));
            SXSSFRow row = sheet.createRow(i);
            /****第0列值，都为唯一key */
            SXSSFCell cell = row.createCell(0);
            cell.setCellValue(excelOnlyKey_1);
            /****第0列值赋值结束 */
            int cellIndex = 0;//下标计数
            for (int k = 0; k < excel1Add2Head.size(); k++) {
                /******************** 第1列赋值 李四 ***************************************/
                cell = row.createCell(cellIndex + 1);
                String headName = excel1Add2Head.get(k);//表头名称
                String cell1Value = row_excelFileData_1.get(headName);//根据表头名称取数据值
                cell.setCellValue(cell1Value);//单元格赋值
//                CellStyle cellStyle1;
                //i==0 代表第一行。这里是将两个excel的表头差集部分标记颜色
                if (i == 0) {
                    //head只在excel1存在；head1SetIntersection 是excel1的表头，在excel2不存的差集
                    for (String str : head1SetIntersection) {
                        if (str.equals(headName)) {
                            cell.setCellStyle(SKY_BLUE_GROUND);
                        }
                    }
                    //head只在excel2存在，head2SetIntersection 是excel2的表头，在excel1不存的差集
                    for (String str : head2SetIntersection) {
                        if (str.equals(headName)) {
                            cell.setCellStyle(LIGHT_BLUE_GROUND);
                        }
                    }
                }
                /******************** 第1列赋值 李四 结束***************************************/

                /******************** 第2列赋值 小王 开始***************************************/
                //excel_1的唯一key,excelOnlyKey_1在excel_2存不存在
                Map<String, String> row_excelFileData_2 = excelOnlyKey_FileData_2.get(excelOnlyKey_1);//excel_1的唯一key,在excel_2存不存在
                //如果组合值的key,只在sheet1存在，对第一列的格子李四设置颜色
                if (row_excelFileData_2 == null && i != 0) {
                    cell.setCellStyle(PINK_GROUND);
                }
                cell = row.createCell(cellIndex + 2);
                String cell2Value = null;
                //如果组合值的key,只在sheet1存在，对第2列的格子小王设置颜色
                if (row_excelFileData_2 == null) {
                    cell.setCellStyle(PINK_GROUND);
                    cell.setCellValue("NA");
                } else {
                    cell2Value = row_excelFileData_2.get(headName);
                    cell.setCellValue(cell2Value);
                }
                ////i==0 代表第一行表头。这里是将两个excel的表头差集部分标记颜色
                if (i == 0) {
                    CellStyle cellStyle2;
                    //只在excel1存在
                    for (String str : head1SetIntersection) {
                        if (str.equals(headName)) {
                            cell.setCellStyle(SKY_BLUE_GROUND);
                        }
                    }
                    //head只在excel2存在
                    for (String str : head2SetIntersection) {
                        if (str.equals(headName)) {
                            cell.setCellStyle(LIGHT_BLUE_GROUND);
                        }
                    }
                }
                /******************** 第2列赋值 小王 结束***************************************/

                /******************** 第3列赋值 比较值是否一致 开始***************************************/
                cell = row.createCell(cellIndex + 3);
                cell.setCellType(CellType.STRING);
                //1.两个值都为"",结果是true 2.两个去空格后值一样，结果为true 3.去空格后，结果不一样，为false
                if (cell1Value != null && cell2Value != null) {
                    if ("".equals(cell1Value) && "".equals(cell2Value)) {
                        cell.setCellValue(this.RESULT_TRUE);//1.两个值都为"",结果是true
                    } else if (cell1Value.trim().equals(cell2Value.trim())) {
                        cell.setCellValue(this.RESULT_TRUE);//2.去空格后，两个都为"",结果是true
                    }else{
                        cell.setCellValue(this.RESULT_FALSE);
                        cell.setCellStyle(RED_FONT);
                        compareFlag=false;//一行数据，如果有一条为false,则需要添加到比较结果不一致的集合
                    }
                //4.左边空，右边实际有值，结果false
                } else if (cell1Value == null && cell2Value != null && !"".equals(cell2Value.trim())) {
                    cell.setCellValue(RESULT_FALSE);
                    cell.setCellStyle(RED_FONT);
                    compareFlag=false;//一行数据，如果有一条为false,则需要添加到比较结果不一致的集合
                    //5.右边空，做边实际有值，结果false
                } else if (cell1Value != null && cell2Value == null&& !"".equals(cell1Value.trim())) {
                    cell.setCellValue(RESULT_FALSE);
                    cell.setCellStyle(RED_FONT);
                    compareFlag=false;//一行数据，如果有一条为false,则需要添加到比较结果不一致的集合
                } else {
                    //6.左右都空，结果true 7.左右有一个为空，一个为空格，结果true
                    cell.setCellValue(RESULT_TRUE);
                }

                if (row_excelFileData_2 == null) {
                    cell.setCellValue("NA");
                    cell.setCellStyle(PINK_GROUND);
                    compareFlag=true;//一行数据，如果有一条为false,则需要添加到比较结果不一致的集合

                }
                cellIndex = cellIndex + 3;
            }
            if (i == 0) {
                this.excelFileCompareFalseData.add(row_excelFileData_1);
            }
            if (!compareFlag) {
                this.excelFileCompareFalseData.add(row_excelFileData_1);
            }
            /******************** 第3列赋值 比较值是否一致 结束***************************************/
        }//for 循环结束
        if (!isCreateExcel2Date) {
            return sheet;
        }

        /********************差集部分，即excel1跟excel2连接，excel2多余的部分  开始*************************/
        int beginRowId = excelFileData_1.size();//要数据连续，要从excel1Data.size()行开始写
        //excelIntersection_2 excel2比excel2多的数据
        for (String s : excelIntersection_2) {
            SXSSFRow row = sheet.createRow(beginRowId);//创建一行
            beginRowId++;
            ///////////第0个列赋值，开始////////////////////////////
            SXSSFCell cell = row.createCell(0);
            cell.setCellValue(s);
            ///////////第0个列赋值，结束////////////////////////////

            int cellIndex = 0;//下标计数
            //从第二列开始，根据head,取map值，赋值到表格
            for (int k = 0; k < excel1Add2Head.size(); k++) {
                String headName = excel1Add2Head.get(k);
                /************************* 从第1列，开始***************************/
                cell = row.createCell(cellIndex + 1);
                cell.setCellType(CellType.STRING);
                cell.setCellStyle(LIGHT_YELLOW_GROUND);
                cell.setCellValue("NA");
                /************************* 从第1列，结束***************************/

                /************************* 从第2列，开始***************************/
                Map<String, String> excelOnlyKey_FileData_2_rowData = excelOnlyKey_FileData_2.get(s);
                cell = row.createCell(cellIndex + 2);
                cell.setCellType(CellType.STRING);
                cell.setCellStyle(LIGHT_YELLOW_GROUND);
                if (excelOnlyKey_FileData_2_rowData == null) {
                    cell.setCellValue("NA");//理论上这里不会NA
                } else {
                    String sheet2Value = null;
                    sheet2Value = excelOnlyKey_FileData_2_rowData.get(headName);
                    cell.setCellValue(sheet2Value);
                }
                /************************* 从第2列，结束***************************/
                /************************* 从第3列，开始***************************/
                cell = row.createCell(cellIndex + 3);
                cell.setCellValue("NA");//默认NA
                cell.setCellStyle(LIGHT_YELLOW_GROUND);
                cellIndex = cellIndex + 3;
                /************************* 从第3列，结束***************************/
            }
        }
        return sheet;
    }

    public Map<String, CellStyle> setCellStyleMap(SXSSFWorkbook workbook) {
        Map<String, CellStyle> cellStyleMap = new HashMap<>();
        //红色字体
        CellStyle redFontStyle = workbook.createCellStyle();
        Font font = workbook.createFont();
        font.setColor(HSSFColor.HSSFColorPredefined.RED.getIndex());
        redFontStyle.setFont(font);
        cellStyleMap.put("RED_FONT", redFontStyle);
        //红色背景
        CellStyle RED_GroundStyle = workbook.createCellStyle();
        RED_GroundStyle.setFillForegroundColor(HSSFColor.HSSFColorPredefined.RED.getIndex());
        RED_GroundStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
        cellStyleMap.put("RED_GROUND", RED_GroundStyle);
        //SKY_BLUE背景
        CellStyle SKY_BLUE_GroundStyle = workbook.createCellStyle();
        SKY_BLUE_GroundStyle.setFillForegroundColor(HSSFColor.HSSFColorPredefined.SKY_BLUE.getIndex());
        SKY_BLUE_GroundStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
        cellStyleMap.put("SKY_BLUE_GROUND", SKY_BLUE_GroundStyle);
        //LIGHT_BLUE背景
        CellStyle LIGHT_BLUE_GroundStyle = workbook.createCellStyle();
        LIGHT_BLUE_GroundStyle.setFillForegroundColor(HSSFColor.HSSFColorPredefined.LIGHT_BLUE.getIndex());
        LIGHT_BLUE_GroundStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
        cellStyleMap.put("LIGHT_BLUE_GROUND", LIGHT_BLUE_GroundStyle);
        //PINK背景
        CellStyle PINK_BLUEGroundStyle = workbook.createCellStyle();
        PINK_BLUEGroundStyle.setFillForegroundColor(HSSFColor.HSSFColorPredefined.PINK.getIndex());
        PINK_BLUEGroundStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
        cellStyleMap.put("PINK_GROUND", PINK_BLUEGroundStyle);
        //LIGHT_YELLOW背景
        CellStyle LIGHT_YELLOW_BLUEGroundStyle = workbook.createCellStyle();
        LIGHT_YELLOW_BLUEGroundStyle.setFillForegroundColor(HSSFColor.HSSFColorPredefined.LIGHT_YELLOW.getIndex());
        LIGHT_YELLOW_BLUEGroundStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
        cellStyleMap.put("LIGHT_YELLOW_GROUND", LIGHT_YELLOW_BLUEGroundStyle);

        return cellStyleMap;
    }


}
